//
// Created by tongj on 24-10-31.
//
#include <math/math.h>
#include <thread>
#include <sstream>

using namespace std;
//移位进位法
string mul(string left, string right) {
  size_t Lsize = left.size();        //size_t = unsigned int
  size_t Rsize = right.size();
  size_t Size = Lsize + Rsize;    //最长位数
  string res(Size, '0');

  int takevoer = 0;//进位
  int offset = 0;//移位

  size_t idx = 1, j = 1;
  for (idx = 1; idx <= Rsize; ++idx) {
    takevoer = 0;
    int rightnum = right[Rsize - idx] - '0';
    //计算每一位与left相乘
    for (j = 1; j <= Lsize; ++j) {
      char resBit = res[Size - j - offset] - '0';        //取res存储对应位的数字
      int num = rightnum * (left[Lsize - j] - '0') + takevoer + resBit;//将两个数相乘，将进位和数组内存的数加入
      takevoer = num / 10;
      res[Size - j - offset] = num % 10 + '0';        //先把个位存进去
    }
    if (takevoer != 0)
      res[Size - j - offset] = takevoer + '0';
    offset++;
  }

  //如果没有进位的话，res最高位没有数字
  if (res[0] == '0')
    res.erase(0, 1);
  return res;
}

namespace tbs::math {

Decimal &Decimal::operator+=(const Decimal &other) {
  if (other.isNegative() != this->isNegative()) {
    Decimal o(other);
    o.reverse();
    return *this -= o;
  }
  int base = _context->getBase();
  auto maxScale = std::max(this->availableScale(), other.availableScale()) + 1;
  auto maxAcc = std::max(this->avaliableAccuracy(), other.avaliableAccuracy());
  this->scale(maxScale);
  this->accuracy(maxAcc);
  int carry = 0;
  this->operateAll([&](char &v, CONST int &i) -> bool {
    auto b = other.seekBitFromDecimals(i);
    v += b + carry;
    if (v >= base) {
      carry = 1;
      v -= base;
    } else
      carry = 0;
    return true;
  }, DECIMAL);
  this->operateAll([&](char &v, CONST int &i) -> bool {
    auto b = other.seekBitFromIntegers(i);
    v += b + carry;
    if (v >= base) {
      carry = 1;
      v -= base;
    } else
      carry = 0;
    return true;
  }, INTEGER);
  return *this;
}

Decimal &Decimal::operator-=(const Decimal &other) {
  *this = *this - other;
  return *this;
}

Decimal &Decimal::operator*=(const Decimal &) {

}
Decimal &Decimal::operator/=(const Decimal &) {

}

Decimal Decimal::operator+(const Decimal &other) const {
  if (other.isNegative() != this->isNegative()) {
    Decimal o(other);
    o.reverse();
    return *this - o;
  }
  int base = _context->getBase();
  auto maxScale = std::max(this->availableScale(), other.availableScale()) + 1;
  auto maxAcc = std::max(this->avaliableAccuracy(), other.avaliableAccuracy());
  Decimal result(0);
  result.scale(maxScale);
  result.accuracy(maxAcc);
  int carry = 0;
  for (int i = maxAcc - 1; i >= 0; i--) {
    auto a = this->seekBitFromDecimals(i);
    auto b = other.seekBitFromDecimals(i);
    a = a + b + carry;
    if (a >= base) {
      carry = 1;
      a -= base;
    } else
      carry = 0;
    result.setBitFromDecimals(i, a);
  }
  for (int i = 0; i < maxScale; i++) {
    auto a = this->seekBitFromIntegers(i);
    auto b = other.seekBitFromIntegers(i);
    a = a + b + carry;
    if (a >= base) {
      carry = 1;
      a -= base;
    } else
      carry = 0;
    result.setBitFromIntegers(i, a);
  }
  return result;
}

Decimal Decimal::operator-(const Decimal &other) const {
  if (other.isNegative() != this->isNegative()) {
    Decimal o(other);
    o.reverse();
    return *this + o;
  }
  int base = _context->getBase();
  int cmp = absCompare(*this, other);
  if (cmp == 0) {
    return {0};
  }
  CONST
  Decimal *smaller, *bigger;
  if (cmp < 0) {
    smaller = this;
    bigger = &other;
  } else {
    smaller = &other;
    bigger = this;
  }
  int maxAcc = std::max(avaliableAccuracy(), other.avaliableAccuracy());
  int carry = 0;
  Decimal result(0);
  for (int i = maxAcc - 1; i >= 0; i--) {
    auto a = bigger->seekBitFromDecimals(i);
    auto b = smaller->seekBitFromDecimals(i);
    a = a - b + carry;
    if (a < 0) {
      a += base;
      carry = -1;
    } else {
      carry = 0;
    }
    result.setBitFromDecimals(i, a);
  }
  int maxScale = std::max(availableScale(), other.availableScale());
  for (int i = 0; i < maxScale; i++) {
    auto a = bigger->seekBitFromIntegers(i);
    auto b = smaller->seekBitFromIntegers(i);
    a = a - b + carry;
    if (a < 0) {
      a += base;
      carry = -1;
    } else {
      carry = 0;
    }
    result.setBitFromIntegers(i, a);
  }
  if (bigger->isNegative()) {
    result.toNegative();
  }
  return result;
}

Decimal Decimal::operator*(const Decimal &other) const {
  int aAcc = this->avaliableAccuracy();
  int bAcc = other.avaliableAccuracy();

  if (aAcc > 0 || bAcc > 0) {
    Decimal result("0", _context);
    this->magicallyMoveDecimal(aAcc, [&](CONST Decimal &a) -> void {
      other.magicallyMoveDecimal(bAcc, [&](CONST Decimal &b) -> void {
        result = a * b;
      });
    });
    result.moveDecimal(-(aAcc + bAcc));
    return result;
  }
  Decimal result = Decimal(mul(this->toString(), other.toString()).c_str(), _context);
  result.positiveAndNegativeMarkings = this->positiveAndNegativeMarkings * other.positiveAndNegativeMarkings;
  return result;
}

Decimal Decimal::operator/(const Decimal &) const {
}

}